﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ARR.Entities.ComponentModel;
using ARR.Shared;
using System.Reflection;

namespace ARR.Entities.Validation.Common
{
    [Serializable]
    public class Range : ValidationBase
    {
        bool includeLimits;
        double? max;
        double? min;

        public Range(string propertyName, double? min, double? max, bool includeLimits, bool isCurrency, string displayName = null) : base(propertyName, null)
        {
            string fieldName = displayName == null ? propertyName : displayName;

            string numberFormat = isCurrency ? Constants.StringFormats.CurrencyTwoDecimals : Constants.StringFormats.NumberTwoDecimals;

            if (max.HasValue && min.HasValue)
            {
                base.ErrorMessage = string.Format(Errors.RangeValidation, fieldName, min.Value.ToString(numberFormat), max.Value.ToString(numberFormat));
            }
            else
            {
                if (min.HasValue)
                {
                    string message = includeLimits ? Errors.GreaterOrEqualThanValidation : Errors.GreaterThanValidation;
                    base.ErrorMessage = string.Format(message, fieldName, min.Value.ToString(numberFormat));
                }

                if (max.HasValue)
                {
                    string message = includeLimits ? Errors.LessOrEqualThanValidation : Errors.LessThanValidation;
                    base.ErrorMessage = string.Format(message, fieldName, max.Value.ToString(numberFormat));
                }
            }

            this.max = max;
            this.min = min;
            this.includeLimits = includeLimits;
        }

        public override bool Validate(ValidatableEntity entity)
        {
            PropertyInfo pi = entity.GetType().GetProperty(this.PropertyName);
            if (pi == null)
                throw new Exception(string.Format("The Property '{0}' is not a valid property name", this.PropertyName));
            object value = pi.GetValue(entity, null);

            if (value is IComparable)
            {
                double numValue;
                if (double.TryParse(value.ToString(), out numValue))
                {
                    if (max.HasValue && min.HasValue)
                    {
                        return includeLimits ? numValue <= max && numValue >= min : numValue < max && numValue > min;
                    }

                    if (min.HasValue)
                    {
                        return includeLimits ? numValue >= min : numValue > min;
                    }


                    if (max.HasValue)
                    {
                        return includeLimits ? numValue <= max : numValue < max;
                    }
                }

                return false;
            }

            throw new ARRException(string.Format("Se esta intentando usar la validación de rango en la propiedad {0} que no es numerica.", PropertyName));
        }
    }
}
